import { EVector2, EVector3 } from "../engine/Math";
import { DIR, OPPSITE_DIR } from "../cfw/tools/Define";
import Utils from "../cfw/tools/Utils";
import { MoveBody } from "./MoveBody";
export class MoveHelper {
    static isRectCollideRect2(x1: number, width1: number, x2: number, width2: number) {
        let flag = !(x2 + width2 < x1 || x2 > x1 + width1);
        return flag;
    }
    /**
  * 角色普通攻击碰撞，调用者是攻击者
  * @param attackRange 攻击者的攻击范围
  * @param behiter 被攻击者
  * @returns 
  */
    static isTargetCollide(attackRange: EVector3, attacker: MoveBody, behiter: MoveBody, faceDir: DIR) {
        let d = OPPSITE_DIR[faceDir]
        let x1 = attacker.getX();
        let y1 = attacker.getY()

        let rw: number = attackRange.x;
        let h: number = attackRange.y;

        let left1 = x1 - d * rw;
        let right1 = left1 + rw;
        let up1 = y1 + h;
        let down1 = y1;

        // Debug.log('x1  ', x1, 'y1 ', y1, 'z1 ', z1)
        let x2 = behiter.getX();
        let y2 = behiter.getY();
        let z2 = behiter.getZ();
        let hw = behiter.getWidth() / 2;
        let height = behiter.getHeight();
        let hz = behiter.getDepth() / 2;
        let left2 = x2 - hw;
        let right2 = x2 + hw;
        let up2 = y2 + height;
        let down2 = y2;

        let rd: number = attackRange.z;
        if (rd == 0) {
            return Utils.isRectCollideRect(left1, right1, up1, down1, left2, right2, up2, down2)
        }
        let z1 = attacker.getZ();
        let inner1 = z1 + rd;
        let outer1 = z1 - rd;
        let inner2 = z2 + hz;
        let outer2 = z2 - hz;
        // Debug.log('x2  ', x2, 'y2 ', y2, 'z2 ', z2)
        return Utils.isRectCollideRect3(left1, right1, up1, down1, inner1, outer1, left2, right2, up2, down2, inner2, outer2)
    }

    /**
     * 目标是否在攻击范围内。
     * @param rw 
     * @param h 
     * @param rd 
     * @param target 
     */
    static isTargetInAttackCuboid(attackRange: EVector3, attacker: MoveBody, target: MoveBody, isIgnoreDir: boolean, faceDir: DIR) {
        if (!attackRange) {
            return true;
        }
        let x1 = attacker.getX();
        let y1 = attacker.getY()


        let rw: number = attackRange.x;
        let h: number = attackRange.y;

        let left = 0;
        let right = 0;
        if (isIgnoreDir) {
            left = x1 - rw;
            right = x1 + rw;
        } else {
            let d = OPPSITE_DIR[faceDir]
            left = x1 - d * rw;
            right = left + rw;
        }
        let up = y1 + h;
        let down = y1;



        let x2 = target.getX();
        let y2 = target.getY();
        let f1 = x2 >= left && x2 <= right;
        let f2 = y2 >= down && y2 <= up;


        let rd: number = attackRange.z;
        if (rd == 0) {
            return f1 && f2
        }
        let z1 = attacker.getZ();
        let inner = z1 + rd;
        let outer = z1 - rd;
        let z2 = target.getZ();
        let f3 = z2 >= outer && z2 <= inner;

        // Debug.warn('isTargetInAttackCuboid  ', f1, 'f2', f2, 'f3', f3, 'x2', x2, 'y2', y2, 'z2', z2, 'left', left, 'right', right, 'down', down, 'up', up, 'outer', outer, 'inner', inner)
        return f1 && f2 && f3
    }


    /**
     * 两个角色的矩形碰撞
     * @param target 被碰撞的对象
     * @returns 
     */
    static isRectCollideAnchorScale(attacker: MoveBody, target: MoveBody) {
        let lx = target.getX();
        let ly = target.getY();
        let lw = target.getWidth();
        let lh = target.getHeight();
        let lax = target.getAnchorX();
        let lay = target.getAnchorY();
        let ls = target.getScale();

        let rx = attacker.getX();
        let ry = attacker.getY();
        let rw = attacker.getWidth();
        let rh = attacker.getHeight();
        let rax = attacker.getAnchorX();
        let ray = attacker.getAnchorY();
        let rs = attacker.getScale();
        let flag = Utils.isRectCollideAnchorScale(lx, ly, lw, lh, lax, lay, ls, rx, ry, rw, rh, rax, ray, rs)
        // Debug.warn('isRectCollideAnchorScale flag ', flag, lx, ly, lw, lh, lax, lay, ls, rx, ry, rw, rh, rax, ray, rs)
        if (flag) {
            return this.isInDistanceZ(attacker, target)
        }
    }


    static isInDistanceX(attacker: MoveBody, target: MoveBody) {
        let dis = Math.abs(target.getX() - attacker.getX())
        let width = (target.getWidth() + attacker.getWidth()) / 2;
        return dis <= width
    }

    static isInDistanceZ(attacker: MoveBody, target: MoveBody) {
        // let disz = Math.abs(this.getZ() - move.getZ());
        // let depth = (move.getDepth() + this.getDepth()) / 2;
        let dz = attacker.getZ();
        if (dz == 0) {
            return true;
        }
        let hh = target.getDepth() / 2;
        let up = target.getZ() + hh;
        let down = target.getZ() - hh;

        let flag = dz >= down && dz <= up;
        // Debug.warn(' isInDistanceZ ', flag)
        return flag
        // return disz <= depth
    }

    /**
 * y方向上使用多边形碰撞
 * z方向上两边缘相交即可
 * @param points MoveComponent的坐标
 * @returns 
 */
    static polygonPolygon(points: EVector2[], attacker: MoveBody, target: MoveBody) {
        if (points && points.length > 0) {
            if (attacker.getShap()) {
                let flag = attacker.getShap().pointsCollideShape(points, attacker.getX(), attacker.getY())
                if (flag) {
                    // console.log('polygonPolygon  flag ', flag)
                    // let dis = Math.abs(this.getZ() - move.getZ());
                    // console.log(' dis ', dis, (move.getDepth() + this.getDepth()) / 2)
                    return this.isInDistanceZ(attacker, target)
                    // console.log("point, this._shape.points ", point, this._shape.points)
                }
                return flag;
            }
        } else {
            return this.isRectCollideAnchorScale(attacker, target)
        }

        return false;
    }

    /**
     * 角色普通攻击碰撞或者与子弹碰撞
     * @param behiter 被攻击者
     * @param attackRange 攻击者的范围
     * @returns 
     */
    static isCollide(attacker: MoveBody, behiter: MoveBody, faceDir: DIR, attackRange?: EVector3) {
        if (attackRange) {
            return this.isTargetCollide(attackRange, attacker, behiter, faceDir)
        } else {
            return this.isRectCollideAnchorScale(attacker, behiter)
        }
    }

    /**
 * 点在矩形上。
 * @param x 
 * @param y 
 * @param z 
 * @returns 
 */
    static pointTopRange(attacker: MoveBody, x: number, y: number, z: number) {
        let by = attacker.getBottom()
        let ty = attacker.getTop()
        let lx = attacker.getLeft();
        let rx = attacker.getRight()
        let iz = attacker.getInner();
        let uz = attacker.getOutter();
        // 
        let xf = x >= lx && x <= rx;
        let yf = y >= ty
        let zf = z <= iz && z >= uz;
        // console.log('  ty, y ', by, y)
        // console.log('  xf, yf, zf', xf, yf, zf)
        return xf && yf && zf
    }


    static getDistance(attacker: MoveBody, move: MoveBody) {
        let dis = move.getX() - attacker.getX()
        let disz = attacker.getZ() - move.getZ();
        return Math.sqrt(dis * dis + disz + disz)
    }

    /**
 * 点在多边形中。
 * @param x 
 * @param y 
 * @param z 
 * @returns 
 */
    static pointInPolygonByWorldPosition(attacker: MoveBody, x: number, y: number, z: number) {
        if (attacker.getShap()) {
            let flag = attacker.getShap().pointInShapeByWorldPoition(x, y, z)
            if (!flag) {
                // console.log("point, this._shape.points ", point, this._shape.points)
            }
            return flag;
        } else {
            let by = attacker.getBottom()
            let ty = attacker.getTop()
            let lx = attacker.getLeft();
            let rx = attacker.getRight()
            let iz = attacker.getInner();
            let uz = attacker.getOutter();
            // console.log(' lx, rx, bz, tz, x, y ', lx, rx, by, ty, x, y)
            return x >= lx && x <= rx && y >= by && y <= ty && z <= iz && z >= uz
        }
    }
    /**
     * 点在多边形中。
     * @param x 
     * @param y 
     * @param z 
     * @returns 
     */
    static pointInPolygon(attacker: MoveBody, x: number, y: number, z: number) {
        if (attacker.getShap()) {
            let flag = attacker.getShap().pointInShape(x, z)
            if (!flag) {
                // console.log("point, this._shape.points ", point, this._shape.points)
            }
            return flag;
        } else {
            let by = attacker.getBottom()
            let ty = attacker.getTop()
            let lx = attacker.getLeft();
            let rx = attacker.getRight()
            let iz = attacker.getInner();
            let uz = attacker.getOutter();
            // console.log(' lx, rx, bz, tz, x, y ', lx, rx, by, ty, x, y)
            return x >= lx && x <= rx && y >= by && y <= ty && z <= iz && z >= uz
        }
    }

    static getDir(attacker: MoveBody, npc: MoveBody) {
        let dh = npc.getHeight() / 3;
        let dw = npc.getWidth() / 3;
        if (Math.abs(npc.getTop() - attacker.getBottom()) <= dh) {
            return DIR.DOWN
        } else if (Math.abs(npc.getLeft() - attacker.getRight()) <= dw) {
            return DIR.RIGHT
        } else if (Math.abs(npc.getRight() - attacker.getLeft()) <= dw) {
            return DIR.LEFT
        } else if (Math.abs(npc.getBottom() - attacker.getTop()) <= dh) {
            return DIR.UP
        } else {
            return DIR.NONE;
        }

    }

    protected static tempRatio: EVector2 = new EVector2(1, 1)
    /**
     * 获得一个物体向两一个物体移动时需要的速度方向
     * @param attacker 
     * @param move 
     * @param out 
     * @returns 
     */
    static getRatio(attacker: MoveBody, move: MoveBody, out?: EVector2) {
        let tx = move.getX();
        let tz = move.getZ();
        let mx = attacker.getX();
        let mz = attacker.getZ();
        let disx = tx - mx;
        let disz = tz - mz;
        let total = Math.sqrt(disx * disx + disz * disz)
        // Debug.log(" disx, disz, total ", disx, disz, total)
        if (total > 0) {
            if (disx == 0) {
                this.tempRatio.y = 1;
                this.tempRatio.x = 0;
            } else if (disz == 0) {
                this.tempRatio.y = 1;
                this.tempRatio.x = 0;
            } else {
                this.tempRatio.x = disx / total;
                this.tempRatio.y = disz / total;
            }

        } else {
            this.tempRatio.x = 0;
            this.tempRatio.y = 0;
        }

        if (out) {
            out.x = this.tempRatio.x;
            out.y = this.tempRatio.y;
        }
        return this.tempRatio;

    }
}